﻿using System;

namespace LAPI.Business.Gestores
{
    /// <summary>
    /// Clase que implementa funciones para gestionar operaciones sobre la entidad de base de datos 'Usuarios'
    /// </summary>
    public class GestorUsuarios
    {
        /// <summary>
        /// Logger de la clase
        /// </summary>
        private LAPI.Core.Logging.ILogger logger;

        /// <summary>
        /// Constructor
        /// </summary>
        public GestorUsuarios()
        {
            logger = LAPI.Core.Logging.LoggerFactory.CreateLogger(type: typeof(GestorUsuarios));
        }

        #region Getter
        /// <summary>
        /// Método para obtener un listado de todos los usuarios activos
        /// </summary>
        /// <returns>Una colección del modelo Usuario con todos los usuarios activos</returns>
        public System.Collections.Generic.List<LAPI.Data.Model.Usuario> ObtenerTodosUsuarios()
        {
            System.Text.StringBuilder sql = new System.Text.StringBuilder();
            LAPI.Data.GestorBBDD oBBDD = LAPI.Data.GestorBBDDFactory.getGestorBBDD();
            System.Collections.Generic.List<LAPI.Data.Model.Usuario> result;

            sql.Append("Select ");
            sql.Append(LAPI.Data.Model.Usuario.Columns);
            sql.Append(" from ");
            sql.Append(LAPI.Data.Model.Usuario.Table);
            sql.Append(" where activo = 1");

            try
            {
                oBBDD.Abrir();
                result = toModel(oBBDD.Select(sql.ToString()));
                oBBDD.CerrarParcial();
                return result;
            }
            catch (Exception ex)
            {
                oBBDD.Cerrar();
                logger.Error(message: ex.Message, exception: ex);
                return null;
            }           
        }

        /// <summary>
        /// Método para obtener los datos de un usuario, sabiendo su identificador único
        /// </summary>
        /// <param name="IdUsuario">Int con el identificador único del usuario</param>
        /// <returns>modelo Usuario con los datos</returns>
        public LAPI.Data.Model.Usuario ObtenerUsuarioPorID(Int32 IdUsuario)
        {
            System.Text.StringBuilder sql = new System.Text.StringBuilder();
            LAPI.Data.GestorBBDD oBBDD = LAPI.Data.GestorBBDDFactory.getGestorBBDD();
            System.Collections.Generic.List<LAPI.Data.Model.Usuario> result;

            sql.Append("Select ");
            sql.Append(LAPI.Data.Model.Usuario.Columns);
            sql.Append(" from ");
            sql.Append(LAPI.Data.Model.Usuario.Table);
            sql.Append(" where activo = 1");

            try
            {
                oBBDD.Abrir();
                result = toModel(oBBDD.Select(sql.ToString()));
                oBBDD.CerrarParcial(); 
                return result[0];
            }
            catch (Exception ex)
            {
                oBBDD.Cerrar();
                logger.Error(message: ex.Message, exception: ex);
                return null;
            }
        }

        /// <summary>
        /// Método para obtener los datos de un usuario, sabiendo su nombre de usuario
        /// </summary>
        /// <param name="nombreUsuario">String con el nombre del usuario</param>
        /// <returns>modelo Usuario con los datos</returns>
        public LAPI.Data.Model.Usuario ObtenerUsuarioPorNombreUsuario(String nombreUsuario)
        {
            System.Text.StringBuilder sql = new System.Text.StringBuilder();
            LAPI.Data.GestorBBDD oBBDD = LAPI.Data.GestorBBDDFactory.getGestorBBDD();
            System.Collections.Generic.List<LAPI.Data.Model.Usuario> result;

            sql.Append("Select ");
            sql.Append(LAPI.Data.Model.Usuario.Columns);
            sql.Append(" from ");
            sql.Append(LAPI.Data.Model.Usuario.Table);
            sql.Append(" where activo = 1 and usuario = '" + nombreUsuario + "'");

            try
            {
                oBBDD.Abrir();
                result = toModel(oBBDD.Select(sql.ToString()));
                oBBDD.CerrarParcial();
                if (result.Count == 1)
                    return result[0];
                else
                    return null;
            }
            catch (Exception ex)
            {
                oBBDD.Cerrar();
                logger.Error(message: ex.Message, exception: ex);
                return null;
            }
        }

        /// <summary>
        /// Método para obtener los datos de un usuario, sabiendo su email
        /// </summary>
        /// <param name="email">String con el email del usuario</param>
        /// <returns>modelo Usuario con los datos</returns>
        public LAPI.Data.Model.Usuario ObtenerUsuarioPorEmail(String email)
        {
            System.Text.StringBuilder sql = new System.Text.StringBuilder();
            LAPI.Data.GestorBBDD oBBDD = LAPI.Data.GestorBBDDFactory.getGestorBBDD();
            System.Collections.Generic.List<LAPI.Data.Model.Usuario> result;

            sql.Append("Select ");
            sql.Append(LAPI.Data.Model.Usuario.Columns);
            sql.Append(" from ");
            sql.Append(LAPI.Data.Model.Usuario.Table);
            sql.Append(" where activo = 1 and email = '" + email + "'");

            try
            {
                oBBDD.Abrir();
                result = toModel(oBBDD.Select(sql.ToString()));
                oBBDD.CerrarParcial();
                if (result.Count == 1)
                    return result[0];
                else
                    return null;
            }
            catch (Exception ex)
            {
                oBBDD.Cerrar();
                logger.Error(message: ex.Message, exception: ex);
                return null;
            }
        }
    #endregion

        #region Comprobaciones

        public Boolean EsFederado(LAPI.Data.Model.Usuario datosUsuario)
        {
            System.Text.StringBuilder sql = new System.Text.StringBuilder();
            LAPI.Data.GestorBBDD oBBDD = LAPI.Data.GestorBBDDFactory.getGestorBBDD();
            System.Data.DataSet result;

            sql.Append("Select federado.verificado ");
            sql.Append(" from ");
            sql.Append(" federado, usuario ");
            sql.Append(" where federado.activo = 1 and federadro.id_usuario = usuario.id_usuario ");
            sql.Append(" and usuario.usuario = '" + datosUsuario.User);
            sql.Append(" and usuario.dni = '" + datosUsuario.DNI);

            try
            {
                oBBDD.Abrir();
                result = oBBDD.Select(sql.ToString());
                oBBDD.CerrarParcial();
                if (result.Tables[0].Rows.Count == 1)
                {
                    return result.Tables[0].Rows[0].ToString().Equals("true") || result.Tables[0].Rows[0].ToString().Equals("1") ? true : false;
                }
                else
                {
                    return false;
                }                
            }
            catch (Exception ex)
            {
                oBBDD.Cerrar();
                logger.Error(message: ex.Message, exception: ex);
                return false;
            }
        }

        /// <summary>
        /// Método para validar si las credenciales (usuario/contraseña) corresponden a algún usuario
        /// </summary>
        /// <param name="usuario">String con el valor de nombre de usuario</param>
        /// <param name="contrasena">String con el valor de contraseña de usuario</param>
        /// <returns>modelo Usuario con los datos del usuario autenticado, o null si no hay ninguno que 
        /// corresponda a esas credenciales</returns>
        public LAPI.Data.Model.Usuario ValidarCredencialesUsuario(String usuario, String contrasena)
        {
            System.Text.StringBuilder sql = new System.Text.StringBuilder();
            LAPI.Data.GestorBBDD oBBDD = LAPI.Data.GestorBBDDFactory.getGestorBBDD();
            System.Collections.Generic.List<LAPI.Data.Model.Usuario> result;

            sql.Append("Select ");
            sql.Append(LAPI.Data.Model.Usuario.Columns);
            sql.Append(" from ");
            sql.Append(LAPI.Data.Model.Usuario.Table);
            sql.Append(" where activo = 1");
            sql.Append(" and Usuario = '" + usuario);
            sql.Append("' and Password = '" + contrasena);
            sql.Append("'");

            try
            {
                oBBDD.Abrir();
                result = toModel(oBBDD.Select(sql.ToString()));
                oBBDD.CerrarParcial();
                if (result.Count > 0)
                    return result[0];
                else
                    return null;
            }
            catch (Exception ex)
            {
                oBBDD.Cerrar();
                logger.Error(message: ex.Message, exception: ex);
                return null;
            }  
        }

        /// <summary>
        /// Método para comprobar si existe algún usuario con el email o nombre de usuario indicado
        /// </summary>
        /// <param name="datosUsuario">Modelo con datos de usuario (contiene mínimo email y nombre de usuario)</param>
        /// <returns>False si existe un usuario con ese email o nombre de usuario. True si no ocurre.</returns>
        public Boolean ComprobarUserYEmail(LAPI.Data.Model.Usuario datosUsuario)
        {
            System.Text.StringBuilder sql = new System.Text.StringBuilder();
            LAPI.Data.GestorBBDD oBBDD = LAPI.Data.GestorBBDDFactory.getGestorBBDD();
            Int32 result;

            sql.Append("Select 1");         
            sql.Append(" from ");
            sql.Append(LAPI.Data.Model.Usuario.Table);
            sql.Append(" where activo = 1");
            sql.Append(" and (");
            sql.Append(" usuario = '" + datosUsuario.User);
            sql.Append("' or email = '" + datosUsuario.Email);
            sql.Append("' )");

            try
            {
                oBBDD.Abrir();
                result = oBBDD.Select(sql.ToString()).Tables[0].Rows.Count;
                oBBDD.CerrarParcial(); 
                return result > 0 ? false : true;
            }
            catch (Exception ex)
            {
                oBBDD.Cerrar();
                logger.Error(message: ex.Message, exception: ex);
                return false;
            }
        }

        /// <summary>
        /// Método para comprobar si una direccion de email, pertenece o no a un usuario registrado de LAPI.
        /// </summary>
        /// <param name="datosUsuario">Modelo con los datos de usuario.
        /// <p>
        /// Es obligatorio que datosUsuario tenga valor para 'Email'. 
        /// </p>
        /// <p>
        /// Es opcional que datosUsuario tenga valor para 'IdUsuario'
        /// </p>
        /// </param>
        /// <returns>True si no existe. False si existe</returns>
        public Boolean ComprobarEmail(LAPI.Data.Model.Usuario datosUsuario)
        {
            System.Text.StringBuilder sql = new System.Text.StringBuilder();
            LAPI.Data.GestorBBDD oBBDD = LAPI.Data.GestorBBDDFactory.getGestorBBDD();
            Int32 result;

            sql.Append("Select 1");
            sql.Append(" from ");
            sql.Append(LAPI.Data.Model.Usuario.Table);
            sql.Append(" where activo = 1");
            sql.Append(" and email = '" + datosUsuario.Email + "'");

            if (datosUsuario.IdUsuario != 0)
                sql.Append(" and id_usuario != " + datosUsuario.IdUsuario);

            try
            {
                oBBDD.Abrir();
                result = oBBDD.Select(sql.ToString()).Tables[0].Rows.Count;
                oBBDD.CerrarParcial();
                return result > 0 ? false : true;
            }
            catch (Exception ex)
            {
                oBBDD.Cerrar();
                logger.Error(message: ex.Message, exception: ex);
                return false;
            }
        }
        
        /// <summary>
        /// Método para comprobar si existe algún usuario con el dni indicado
        /// </summary>
        /// <param name="datosUsuario">Modelo con los datos de usuario.
        /// <p>
        /// Es obligatorio que datosUsuario tenga valor para 'DNI'. 
        /// </p>
        /// <p>
        /// Es opcional que datosUsuario tenga valor para 'IdUsuario'
        /// </p>
        /// </param>
        /// <returns>True si no existe. False si existe</returns>
        public Boolean ComprobarDNI(LAPI.Data.Model.Usuario datosUsuario)
        {
            System.Text.StringBuilder sql = new System.Text.StringBuilder();
            LAPI.Data.GestorBBDD oBBDD = LAPI.Data.GestorBBDDFactory.getGestorBBDD();
            Int32 result;

            sql.Append("Select 1");
            sql.Append(" from ");
            sql.Append(LAPI.Data.Model.Usuario.Table);
            sql.Append(" where activo = 1");
            sql.Append(" and  dni = '" + datosUsuario.DNI + "'");

            if (datosUsuario.IdUsuario != 0)
                sql.Append(" and id_usuario != " + datosUsuario.IdUsuario);

            try
            {
                oBBDD.Abrir();
                result = oBBDD.Select(sql.ToString()).Tables[0].Rows.Count;
                oBBDD.CerrarParcial();
                return result > 0 ? false : true;
            }
            catch (Exception ex)
            {
                oBBDD.Cerrar();
                logger.Error(message: ex.Message, exception: ex);
                return false;
            }
        }

        /// <summary>
        /// Método para comprobar si una contraseña corresponde a un usuario indicado
        /// </summary>
        /// <param name="datosUsuario">Modelo con datos de usuario (contiene mínimo identificador de usuario y contraseña)</param>
        /// <returns></returns>
        public Boolean ComprobarContrasena(LAPI.Data.Model.Usuario datosUsuario)
        {
            System.Text.StringBuilder sql = new System.Text.StringBuilder();
            LAPI.Data.GestorBBDD oBBDD = LAPI.Data.GestorBBDDFactory.getGestorBBDD();
            Int32 result;

            sql.Append("Select 1");
            sql.Append(" from ");
            sql.Append(LAPI.Data.Model.Usuario.Table);
            sql.Append(" where activo = 1");
            sql.Append(" and  password = '" + datosUsuario.Password + "'");
            sql.Append(" and id_usuario = " + datosUsuario.IdUsuario);

            try
            {
                oBBDD.Abrir();
                result = oBBDD.Select(sql.ToString()).Tables[0].Rows.Count;
                oBBDD.CerrarParcial();
                return result > 0 ? true : false;
            }
            catch (Exception ex)
            {
                oBBDD.Cerrar();
                logger.Error(message: ex.Message, exception: ex);
                return false;
            }
        }
#endregion

        #region insert

        /// <summary>
        /// Método para insertar un nuevo usuario en la base de datos
        /// </summary>
        /// <param name="datosUsuario">Modelo con los datos del usuario a insertar (previamente validados)</param>
        public void InsertarUsuario(LAPI.Data.Model.Usuario datosUsuario)
        {
            System.Text.StringBuilder sql = new System.Text.StringBuilder();
            LAPI.Data.GestorBBDD oBBDD = LAPI.Data.GestorBBDDFactory.getGestorBBDD();
            Int32 result;

            sql.Append("Insert into ");
            sql.Append(LAPI.Data.Model.Usuario.Table);
            sql.Append(" ( ");
            sql.Append(datosUsuario.ToInsertColumns());
            sql.Append(" ) values ( ");
            sql.Append(datosUsuario.ToInsertValues());
            sql.Append(" ) ");            

            try
            {
                oBBDD.Abrir();
                result = oBBDD.Insert(sql.ToString());               
                oBBDD.CerrarParcial();
                if (result != 1)
                    throw new Exception("No se ha insertado el registro: " +datosUsuario);
            }
            catch (Exception ex)
            {
                oBBDD.Cerrar();
                logger.Error(message: ex.Message, exception: ex);
                throw new Exception("No se ha insertado el registro: " + datosUsuario);
            }           
        }

        #endregion

        #region update

        /// <summary>
        /// Método para actualizar los datos 'cambiantes' del usuario.
        /// </summary>
        /// <param name="datosUsuario">Modelo con los datos actualizados del usuario</param>
        public void ActualizarUsuario(LAPI.Data.Model.Usuario datosUsuario)
        {
            System.Text.StringBuilder sql = new System.Text.StringBuilder();
            LAPI.Data.GestorBBDD oBBDD = LAPI.Data.GestorBBDDFactory.getGestorBBDD();
            Int32 result;

            sql.Append("Update ");
            sql.Append(LAPI.Data.Model.Usuario.Table);
            sql.Append(" set ");
            sql.Append(datosUsuario.ToUpdateDatosUsuario());
            sql.Append(" where activo = 1");
            sql.Append("   and id_usuario =" + datosUsuario.IdUsuario);

            try
            {
                oBBDD.Abrir();
                result = oBBDD.Update(sql.ToString());
                oBBDD.CerrarParcial();
                if (result != 1)
                    throw new Exception("No se ha actualizado el registro: " + datosUsuario);
            }
            catch (Exception ex)
            {
                oBBDD.Cerrar();
                logger.Error(message: ex.Message, exception: ex);
                throw new Exception("No se ha actualizado el registro: " + datosUsuario);
            }
        }

        /// <summary>
        /// Método para actualizar la contraseña del usuario.
        /// </summary>
        /// <param name="datosUsuario">Modelo con la contraseña actualizada del usuario</param>
        public void ActualizarContrasena(LAPI.Data.Model.Usuario datosUsuario)
        {
            System.Text.StringBuilder sql = new System.Text.StringBuilder();
            LAPI.Data.GestorBBDD oBBDD = LAPI.Data.GestorBBDDFactory.getGestorBBDD();
            Int32 result;

            sql.Append("Update ");
            sql.Append(LAPI.Data.Model.Usuario.Table);
            sql.Append(" set ");
            sql.Append(datosUsuario.ToUpdatePasswordUsuario());
            sql.Append(" where activo = 1");
            sql.Append("   and id_usuario =" + datosUsuario.IdUsuario);

            try
            {
                oBBDD.Abrir();
                result = oBBDD.Update(sql.ToString());
                oBBDD.CerrarParcial();
                if (result != 1)
                    throw new Exception("No se ha actualizado el registro: " + datosUsuario);
            }
            catch (Exception ex)
            {
                oBBDD.Cerrar();
                logger.Error(message: ex.Message, exception: ex);
                throw new Exception("No se ha actualizado el registro: " + datosUsuario);
            }
        }
        #endregion

        /// <summary>
        /// Método para convertir un Dataset en el modelo de datos de usuario.
        /// </summary>
        /// <param name="response">Dataset obtenido en la consulta</param>
        /// <returns>Colección con los modelos obtenidos en la conversión</returns>
        private System.Collections.Generic.List<LAPI.Data.Model.Usuario> toModel(System.Data.DataSet response)
        {
            System.Collections.Generic.List<LAPI.Data.Model.Usuario> result = new System.Collections.Generic.List<Data.Model.Usuario>();

            foreach (System.Data.DataRow item in response.Tables[0].Rows)
            {
                LAPI.Data.Model.Usuario model = new Data.Model.Usuario();
                model.IdUsuario = Convert.ToInt32(item["ID_Usuario"]);
                model.IdPermisos = Convert.ToInt32(item["ID_Permisos"]);
                model.Nombre = item["Nombre"].ToString();
                model.Apellido = item["Apellido"].ToString();
                model.Apellido2 = item["Apellido2"].ToString();
                model.DNI = item["DNI"].ToString();
                model.User = item["Usuario"].ToString();
                model.Password = item["Password"].ToString();
                model.fx_registro = Convert.ToDateTime(item["fx_registro"].ToString());
                model.Email = item["email"].ToString();

                result.Add(model);
            }

            return result;
        }

    }
}
